// 引入axios插件
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'
// import { ElMessage } from 'element-plus'

// 使用create 创建axios示例 （当然这里存在很多配置选项，具体需要具体配置）
const instance = axios.create()
// 我在这里直接指定了post请求的 请求类型 Content-Type，  可不设置看需要
instance.defaults.headers.post['Content-Type'] = 'application/json; charset=UTF-8'

// 声明一个数组用于存储每个ajax请求的取消函数和ajax标识
const pending: any = []
const { CancelToken } = axios // axios 内置方法，此方法是为取消请求

// 入参removeAll 为true时，清空数组。
const removePending = (ever: AxiosRequestConfig, removeAll?: boolean) => {
  for (let i = 0; i < pending.length; i += 1) {
    if (removeAll) {
      pending[i].f() // 执行取消操作
      pending.splice(i, 1) // 把这条记录从数组中移除
    } else if (
      pending[i].u === `${ever.url!.replace(/d=\d+/, '')}&${ever.method}`
    ) {
      // 当当前请求在数组中存在时执行函数体
      pending[i].f() // 执行取消操作
      pending.splice(i, 1) // 把这条记录从数组中移除
    }
  }
}

const removeOtherPending = (ever: string, removeAll?: boolean) => {
  for (let i = 0; i < pending.length; i += 1) {
    if (pending[i].u.indexOf(ever) !== -1) {
      // 当当前请求在数组中存在时执行函数体
      pending[i].f() // 执行取消操作
      pending.splice(i, 1) // 把这条记录从数组中移除
    }
  }
}

// http request 拦截器
instance.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    // canMoreActive 参数用来判断是否需要被添加到pending队列中   该参数是设置在请求头中的，需要后台进行配置该参数
    if (!config.headers!.canMoreActive) {
      // 该接口是否可以多并发
      removePending(config) // 在一个ajax发送前执行一下取消操作
      // eslint-disable-next-line no-param-reassign
      config.cancelToken = new CancelToken((c) => {
        // 这里的ajax标识我是用请求地址&请求方式拼接的字符串，当然你可以选择其他的一些方式
        pending.push({
          // 去除添加的日期导致的链接不一致
          u: `${config.url!.replace(/d=\d+/, '')}&${config.method}`,
          f: c,
        })
      })
    }
    return config
  },
  (error: AxiosError) => Promise.reject(error)
)


// 必须在项目中重写该方法，因为如果调用多次use方法，是一个队列，函数都会执行
/* instance.interceptors.response.use(
  (response: AxiosResponse) => {
    removePending(response.config) // 在一个ajax响应后再执行一下取消操作，把已经完成的请求从pending中移除
    if (response.data.code === 700) {
      ElMessage({
        type: 'error',
        message: response.data.msg,
      })
    }
    return response
  },
  (error: AxiosError) => Promise.reject(error)
) */

/**
 * 封装get方法
 * @param url 请求url
 * @param params 参数
 * @param config config参数
 * @returns {Promise}
 */
function fetch(
    url: string,
    params: any = {},
    config = {
        headers: {},
    }
): Promise<any> {
    return new Promise((resolve, reject) => {
        // 参数增加一个随机数解决浏览器缓存问题
        instance.get(`${url}?d=${new Date().getTime()}`, {
            params,
            headers: config.headers, // 设置get请求头，用来传递canMoreActive参数
        }).then((response) => {
            if (response) {
                resolve(response.data)
            }
        }).catch((err) => {
            reject(err)
        })
    })
}

/**
 * 封装post请求
 * @param url 请求url
 * @param data 参数
 * @param config config参数
 * @returns {Promise}
 */
function post(
    url: string,
    params: any = {},
    config = {},
    ContentType = ''
): Promise<any> {
    return new Promise((resolve, reject) => {
        if (ContentType) {
            instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
        } else {
            instance.defaults.headers.post['Content-Type'] = 'application/json; charset=UTF-8'
        }
        instance.post(url, params, config).then((response) => {
            if (response) {
                resolve(response.data)
            }
        }).catch((err) => {
            reject(err)
        })
    })
}

/**
 * 封装 DELETE 请求
 * @param {string} url 请求的URL
 * @param {object} data 请求参数
 * @param {object} config 额外的 Axios 请求配置
 * @returns {Promise<any>}
 */
function del(
    url: string,
    data: any = {},
    config: AxiosRequestConfig = {}
): Promise<any> {
    return new Promise((resolve, reject) => {
        // 发起 DELETE 请求
        // 使用 delete 方法，注意要传递参数在 data 属性中
        instance.delete(url, {...config, data}).then((response: AxiosResponse) => {
            resolve(response.data) // 解析响应数据
        }).catch((error: AxiosError) => {
            reject(error) // 处理请求错误
        })
    })
}

// 全部导出
export { instance, post, fetch, pending, del, removePending, removeOtherPending }